/*
 * JFlex scanner specification for the Bridge Grammar language
 * 
 * Emma Söderberg <emma at cs.lth.se>
 */

package org.bridgen.lang.scanner;

import org.bridgen.lang.parser.*;
import java_cup.runtime.Symbol;

%% 

%public 
%class BridgenScanner
%implements sym 
%unicode
%cup
%line
%column

%{
	StringBuffer string = new StringBuffer();
	StringBuffer code = new StringBuffer();
	
	private Symbol symbol(int type) {
		return new Symbol(type, yyline, yycolumn);
	}
	private Symbol symbol(int type, Object value) {
		return new Symbol(type, yyline, yycolumn, value);
	}
%}

%state STRING
%state JAVA

LineTerminator = \r|\n|\r\n
InputCharacter = [^\r\n]
WhiteSpace = {LineTerminator} | [ \t\f]

Comment = {TraditionalComment} | {EndOfLineComment} | 
          {DocumentationComment}

TraditionalComment = "/*" [^*] ~"*/" | "/*" "*"+ "/"
EndOfLineComment = "//" {InputCharacter}* {LineTerminator}?
DocumentationComment = "/*" "*"+ [^/*] ~"*/"

Identifier = [:jletter:] [:jletterdigit:]*
DecLiteral = 0 | [1-9][:digit:]*

%%

/* Initial state */
<YYINITIAL> {
  
  /* Keywords */
  
  "grammar"     { return symbol(sym.GRAMMAR); }
  "import"      { return symbol(sym.IMPORT); }
  
  "island"		{ return symbol(sym.ISLAND); }
  "reef"        { return symbol(sym.REEF); }
  
  "bridge"      { return symbol(sym.BRIDGE); }
  "from"        { return symbol(sym.FROM); }
  "to"          { return symbol(sym.TO); }
  "when"        { return symbol(sym.WHEN); }
  
  "recover"     { return symbol(sym.RECOVER); }
  "find"        { return symbol(sym.FIND); }
  "where"       { return symbol(sym.WHERE); }
  
  "insert"      { return symbol(sym.INSERT); }
  "after"       { return symbol(sym.AFTER); }
  "before"      { return symbol(sym.BEFORE); }
  
  "attr"        { return symbol(sym.ATTR); }
  "java-attr"   { return symbol(sym.JAVA_ATTR); }
  "left"        { return symbol(sym.LEFT); }
  "right"       { return symbol(sym.RIGHT); }
  "first"       { return symbol(sym.FIRST); }
  "second"      { return symbol(sym.SECOND); }
  "third"       { return symbol(sym.THIRD); }
  
  "abstract"    { return symbol(sym.ABSTRACT); }
  "use-super"   { return symbol(sym.USE_SUPER); }
  "extend"      { return symbol(sym.EXTEND); }
  "ignore"      { return symbol(sym.IGNORE); }
  
  "bridge-end"  { return symbol(sym.BRIDGE_END); }
  "bridge-start" { return symbol(sym.BRIDGE_START); }
  
  "for-sglr"    { return symbol(sym.FOR_SGLR); }
  
  /* Enclosement */
  
  "("           { return symbol(sym.LPAREN); }
  ")"           { return symbol(sym.RPAREN); }
  "["           { return symbol(sym.LBRACK); }
  "]"           { return symbol(sym.RBRACK); }
  
  /* Separators */
  	
  ";"           { return symbol(sym.SEMICOLON); }
  ":"           { return symbol(sym.COLON); }
  
  /* Assignment */
  
  "="           { return symbol(sym.ASSIGN); }
  
  /* Access operator */
  
  "."           { return symbol(sym.DOT); }
  
  /* Matching expressions */
  
  "|"           { return symbol(sym.ALT); }
  "NEWLINE"     { return symbol(sym.NEWLINE); }
  "TAB"         { return symbol(sym.TAB); }
  "WS"          { return symbol(sym.WS); }
  "*"           { return symbol(sym.MULTI); }
  "+"           { return symbol(sym.ONE_MULTI); }
  "?"           { return symbol(sym.OPTIONAL); }
  
  /* Operators */
  
  "&&"          { return symbol(sym.AND); }
  "||"          { return symbol(sym.OR); }
  "!"           { return symbol(sym.NOT); }
  
  "=="          { return symbol(sym.EQ); }
  "!="          { return symbol(sym.NEQ); }
  ">="          { return symbol(sym.GEQ); }
  "<="          { return symbol(sym.LEQ); }
  ">"           { return symbol(sym.GT); }
  "<"           { return symbol(sym.LT); }
  
  /* Identifiers */
  
  {Identifier}  { return symbol(sym.IDENTIFIER, yytext()); }
  
  /* Literals */
  
  {DecLiteral}  { return symbol(sym.INTEGER_LITERAL, yytext()); }
  
  /* Comments */
  
  {Comment}     { /* Ignore */ }
  
  /* Whitespace */
  
  {WhiteSpace}  { /* Ignore */ }
  
  /* Match patterns */
  
  \"            { string.setLength(0); yybegin(STRING); }
  
  /* Java blocks */
  
  "@@"           { code.setLength(0); yybegin(JAVA); }
  
}

/* String state */
<STRING> {

  /* Stop character */

  \"             { yybegin(YYINITIAL); 
                   return symbol(sym.STRING_LITERAL, string.toString()); }

  /* Accepted characters */
  
  [^\n\r\"\\]+   { string.append( yytext() ); }
  \\t            { string.append('\t'); }
  \\n            { string.append('\n'); }
  \\r            { string.append('\r'); }
  \\\"           { string.append('\"'); }
  \\             { string.append('\\'); }
  
}

/* Java block state */
<JAVA> {
  
  /* Stop character */
  
  "@@"           { yybegin(YYINITIAL);
                   return symbol(sym.JAVA_BLOCK, code.toString()); }
                   
  /* Accepted characters */
  
  [^@]+          { code.append( yytext() ); }
  
}

[^]             { throw new Error("lexical error: Illegal character <" + yytext() + 
                               "> at line = " + (yyline+1) + ", column = " + (yycolumn+1)); }


